package com.sh.data.engine.application.service.integration;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import com.google.common.collect.Lists;
import com.sh.data.engine.application.model.dto.base.PagerResponse;
import com.sh.data.engine.application.model.dto.dataasset.FieldInfoDTO;
import com.sh.data.engine.application.model.dto.dataasset.TableInfoBizDTO;
import com.sh.data.engine.application.model.dto.integration.DocumentCaptureDTO;
import com.sh.data.engine.application.model.dto.integration.PreviewDataDTO;
import com.sh.data.engine.application.model.dto.workspace.PortalSiteFileUploadDTO;
import com.sh.data.engine.application.model.mapper.datadev.FieldInfoDTOMapper;
import com.sh.data.engine.application.model.mapper.datadev.TableInfoBizDTOMapper;
import com.sh.data.engine.application.model.mapper.integration.DocumentCaptureDTOPagerMapper;
import com.sh.data.engine.application.model.mapper.integration.SaveTaskWithFromTextParamMapper;
import com.sh.data.engine.application.model.request.integration.CreateSqlRequest;
import com.sh.data.engine.application.model.request.integration.DocumentCaptureCreateSqlRequest;
import com.sh.data.engine.application.model.request.integration.SaveTaskWithFromTextRequest;
import com.sh.data.engine.common.constants.HttpStatus;
import com.sh.data.engine.common.constants.code.BizCodes;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.common.util.ServletUtils;
import com.sh.data.engine.domain.authority.service.DataAuthService;
import com.sh.data.engine.domain.base.model.FileUploadResultDomain;
import com.sh.data.engine.domain.base.model.PageResult;
import com.sh.data.engine.domain.base.model.UserContext;
import com.sh.data.engine.domain.base.model.enums.RightEnum;
import com.sh.data.engine.domain.base.model.enums.ThemeEnum;
import com.sh.data.engine.domain.base.service.FileService;
import com.sh.data.engine.domain.common.service.TableManager;
import com.sh.data.engine.domain.dataasset.model.domain.TableInfoBizDomain;
import com.sh.data.engine.domain.dataasset.service.TblPropService;
import com.sh.data.engine.domain.integration.datasource.model.domain.DataSourceCreateTableDomain;
import com.sh.data.engine.domain.integration.datasource.model.domain.DataSourceDomain;
import com.sh.data.engine.domain.integration.datasource.service.DataSourceService;
import com.sh.data.engine.domain.integration.documentCapture.model.domain.DocumentCaptureDomain;
import com.sh.data.engine.domain.integration.documentCapture.model.param.SaveTaskWithFromTextParam;
import com.sh.data.engine.domain.integration.documentCapture.service.DocumentCaptureService;
import com.sh.data.engine.domain.shims.db.model.FieldInfoDomain;
import com.sh.data.engine.domain.shims.db.model.TableInfoDomain;
import com.sh.data.engine.infrastructure.config.DocumentCaptureConfig;
import com.sh.data.engine.repository.dao.dataasset.entity.TblPropEntity;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author: mengzheng.mhc
 * @date: 2024/6/26 10:04
 */
@Slf4j
@Service
public class DocumentCaptureApplicationService {

    @Autowired
    private DocumentCaptureService documentCaptureService;

    @Autowired
    private FileService fileService;

    @Autowired
    private DataAuthService dataAuthService;

    @Autowired
    private DataSourceService dataSourceService;

    @Autowired
    private TblPropService tblPropService;

    @Autowired
    private TableManager tableManager;

    @Autowired
    private DocumentCaptureConfig documentCaptureConfig;

    @Autowired
    private DocumentCaptureDTOPagerMapper documentCaptureDTOPagerMapper;

    @Autowired
    private TableInfoBizDTOMapper tableInfoBizDTOMapper;

    @Autowired
    private FieldInfoDTOMapper fieldInfoDTOMapper;

    @Autowired
    private SaveTaskWithFromTextParamMapper saveTaskWithFromTextParamMapper;

    public List<List<String>> parseFile(MultipartFile multipartFile, Map<String, String[]> parameterMap) {
        return documentCaptureService.parseFile(multipartFile, parameterMap);
    }

    public PortalSiteFileUploadDTO uploadFile(MultipartFile multipartFile) {
        // 校验文件格式
        String filename = multipartFile.getOriginalFilename();
        filename = filename.toLowerCase();
        if (!(filename.endsWith(".xls") || filename.endsWith(".xlsx") || filename.endsWith(".csv"))) {
            throw new BusinessException(BizCodes.UNSUPPORTED_FILE_FORMAT, HttpStatus.BAD_REQUEST);
        }

        try {
            // 为了保证上穿文件不被同名的文件覆盖 存储的路径为/data/datax/documentCapture/+时间戳
            String filePath = documentCaptureConfig.getDocumentCaptureHome() + System.currentTimeMillis();
            FileUploadResultDomain fileUploadResultDomain = fileService.upload(multipartFile, filePath);

            PortalSiteFileUploadDTO portalSiteFileUploadDTO = new PortalSiteFileUploadDTO();
            portalSiteFileUploadDTO.setFilePath(fileUploadResultDomain.getFilePath());
            portalSiteFileUploadDTO.setFilePreviewUrl(fileUploadResultDomain.getFilePreviewUrl());
            portalSiteFileUploadDTO.setFileDownloadUrl(fileUploadResultDomain.getFileDownloadUrl());
            return portalSiteFileUploadDTO;
        } catch (Exception e) {
            throw new BusinessException("文件上传失败" + e.getMessage());
        }
    }

    public PagerResponse<DocumentCaptureDTO> getCaptureList(String tableName, Integer pageNum, Integer pageSize, Long projectId) {
        PageResult<DocumentCaptureDomain> captureList = documentCaptureService.getCaptureList(tableName, pageNum, pageSize, projectId);
        return documentCaptureDTOPagerMapper.toPageResponse(captureList);
    }

    public List<TableInfoBizDTO> getTableList(Long projectId) {
        List<TableInfoBizDomain> tableList = documentCaptureService.getTableList(projectId);
        return tableInfoBizDTOMapper.map(tableList);
    }

    public List<FieldInfoDTO> getTableField(Long projectId, String tblName) {
        List<FieldInfoDomain> tableFields = tableManager.getTableField(projectId, tblName);
        return fieldInfoDTOMapper.map(tableFields);
    }

    public List<String> getLog(Long docCapId) {
        return documentCaptureService.getLog(docCapId);
    }

    public Boolean del(Long docCapId) {
        return documentCaptureService.del(docCapId);
    }

    public Boolean saveTaskWithFromText(SaveTaskWithFromTextRequest request) {
        // 首先获取项目id和用户id
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();

        if (request.getTblId() != null) {
            String tblAuth = dataAuthService.getTblAuth(projectId, userId, request.getTblId());
            if (!RightEnum.RW.getCode().equals(tblAuth)) {
                throw new BusinessException("您没有该表的写权限");
            }
        }

        SaveTaskWithFromTextParam param = saveTaskWithFromTextParamMapper.map(request);
        param.setProjectId(projectId);
        param.setUserId(userId);

        // 传入编码格式 默认GBK
        if (StringUtils.isBlank(request.getEncodeFormat())) {
            param.setEncodeFormat("GBK");
        }

        return documentCaptureService.saveTaskWithFromText(param);
    }

    public PreviewDataDTO getData(String targetTblName) {
        // 首先获取项目id和用户id
        Long projectId = ServletUtils.getProjectId();
        List<Map<String, Object>> data = tableManager.getDataLimit10(targetTblName, projectId);
        PreviewDataDTO previewDataResponse = new PreviewDataDTO();
        if (data == null || data.size() == 0) {
            // 该表没有数据，只返回字段
            List<FieldInfoDomain> tableField = tableManager.getTableField(projectId, targetTblName);
            List<String> collect =
                tableField.stream().map(FieldInfoDomain::getFieldName).collect(Collectors.toList());
            previewDataResponse.setColumns(collect);
            previewDataResponse.setRows(null);
            return previewDataResponse;
        }

        // 列名集合
        previewDataResponse.setColumns(new ArrayList<>(data.get(0).keySet()));

        // 行记录集合
        List<List<Object>> rows = new ArrayList<>();

        for (Map<String, Object> datum : data) {
            Collection<Object> values = datum.values();
            List<Object> row = new ArrayList<>(values);
            rows.add(row);
        }
        previewDataResponse.setRows(rows);
        return previewDataResponse;
    }

    public TableInfoBizDTO createTable(CreateSqlRequest createSqlRequest) {
        Long projectId = ServletUtils.getProjectId();
        DataSourceDomain systemDataSourceByProjectId = dataSourceService.getSystemDataSourceByProjectId(projectId);
        if (systemDataSourceByProjectId == null) {
            throw new BusinessException("找不到该项目的数据源Id");
        }
        DataSourceCreateTableDomain dataSourceCreateTableDomain =
            dataSourceService.executeCreateTableSql(
                systemDataSourceByProjectId.getId(), createSqlRequest.getScripts());

        TableInfoBizDomain tableBizInfo = new TableInfoBizDomain();

        // 保存tblProp
        TblPropEntity tblPropEntity = new TblPropEntity();
        tblPropEntity.setProjectId(projectId);
        tblPropEntity.setSchema(dataSourceCreateTableDomain.getSchema());
        tblPropEntity.setTblId(tblPropService.generateTblId(projectId));
        tblPropEntity.setDataSecretId(null);
        tblPropEntity.setTableName(dataSourceCreateTableDomain.getOnlyTableName());
        tblPropEntity.setLifecycle(-1);
        tblPropEntity.setTblType(TableInfoDomain.TblType.MANAGED_TABLE.name());
        tblPropEntity.setRowState(1);
        tblPropService.save(tblPropEntity);

        tableBizInfo.setTableName(dataSourceCreateTableDomain.getTableName());
        return tableInfoBizDTOMapper.map(tableBizInfo);
    }

    public String createSql(Integer colNum) {
        Long projectId = ServletUtils.getProjectId();
        String tableName = "ods_file_import_" + RandomUtil.randomString(4);
        List<String> fieldName = new ArrayList<>();

        for (int i = 0; i < colNum; i++) {
            fieldName.add("column" + i);
        }

        String sql = documentCaptureService.createSql(tableName, fieldName, projectId);
        return sql;
    }

    public String createSqlAutoParse(DocumentCaptureCreateSqlRequest request) {
        String name = request.getFileName();
        if (!name.endsWith(".xlsx") && !name.endsWith(".xls") && !name.endsWith(".csv")) {
            throw new BusinessException("仅支持扩展名为xlsx、xls、csv的文件");
        }
        name = name.split("\\.")[0];
        String fileName =
            ThemeEnum.ODS.getCode()
                + "_"
                + PinyinUtil.getFirstLetter(name, StrUtil.EMPTY).toUpperCase();
        List<String> columnNames = request.getColumnNames();
        List<String> convert = Lists.newArrayList();
        for (String s : columnNames) {
            this.concatAndAdd(PinyinUtil.getFirstLetter(s, "").toUpperCase(), 1, convert);
        }
        Long projectId = ServletUtils.getProjectId();
        String sql = documentCaptureService.createSql(fileName, convert, projectId);
        return sql;
    }

    private void concatAndAdd(String s, Integer i, List<String> convert) {
        if (!convert.contains(s)) {
            convert.add(s);
            return;
        }
        if (!convert.contains(s + i)) {
            convert.add(s + i);
            return;
        }
        concatAndAdd(s, ++i, convert);
    }

    public void exportFile(Long id, HttpServletResponse response) {
        documentCaptureService.exportFile(id, response);
    }
}
